package com.example.springbootdemo.util;

import com.example.springbootdemo.bean.dto.ChunkInfoDTO;
import com.example.springbootdemo.bean.model.FileInfo;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @author hh
 * @date 2022/3/1
 */
public class FileUtils {

    public static final String MERGE_FILE_EXIST = "100";
    public static final String MERGE_SUCCESS = "200";
    public static final String MERGE_FAIL = "300";

    private FileUtils() {
    }

    /**
     * 生成文件路径
     * @param path 路径
     * @param chunkInfoDTO chunkInfoDTO
     * @return String
     */
    public static String generatePath(String path, ChunkInfoDTO chunkInfoDTO){
        String hasCheckPath = checkPath(path);
        Objects.requireNonNull(chunkInfoDTO, "chunkInfoDTO cannot be empty");

        StringBuilder newPathBuilder = new StringBuilder(hasCheckPath);
        newPathBuilder.append(chunkInfoDTO.getIdentifier());
        // 判断路径是否存在，不存在则创建
        if (!Files.isWritable(Paths.get(newPathBuilder.toString()))){
            try {
                Files.createDirectories(Paths.get(newPathBuilder.toString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return newPathBuilder.append(File.separator)
                .append(chunkInfoDTO.getFileName())
                .append("-")
                .append(chunkInfoDTO.getChunkNumber())
                .toString();
    }

    /**
     * 文件合并
     * @param filePath 文件路径
     * @param folder 文件夹
     * @param fileName 文件名
     * @return String 100：文件已存在，200：合并成功，300：合并失败
     */
    public static String merge(String filePath, String folder, String fileName) {
        if (fileExists(filePath)){
            return "100";
        }
        try {
            Files.createFile(Paths.get(filePath));

            Files.list(Paths.get(folder))
                    .filter(t -> !t.getFileName().toString().equals(fileName))
                    .sorted((o1, o2) -> {
                        String p1 = o1.getFileName().toString();
                        String p2 = o2.getFileName().toString();
                        int i1 = p1.lastIndexOf("-");
                        int i2 = p2.lastIndexOf("-");
                        return Integer.valueOf(p2.substring(i2 + 1)).compareTo(Integer.valueOf(p1.substring(i1 + 1)));
                    })
                    .forEach(t -> {
                        try {
                            // 以追加的形式写入文件
                            Files.write(Paths.get(filePath), Files.readAllBytes(t), StandardOpenOption.APPEND);

                            // 合并后删除该块
                            Files.delete(t);

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
        } catch (IOException e) {
            e.printStackTrace();
            return "300";
        }
        return "200";
    }

    /**
     * 文件是否存在
     * @param file 文件
     * @return boolean
     */
    public static boolean fileExists(String file){
        return Files.exists(Paths.get(file), LinkOption.NOFOLLOW_LINKS);
    }

    /**
     * 获取文件信息
     * @param file 文件
     * @return FileInfo
     * @throws Exception Exception
     */
    public static FileInfo getFileInfo(MultipartFile file) throws Exception {
        String md5 = fileMd5(file.getInputStream());
        FileInfo fileInfo = new FileInfo();
        // 将文件的md5设置为文件表的id
        fileInfo.setId(md5);
        fileInfo.setName(file.getOriginalFilename());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setIsImg(fileInfo.getContentType().startsWith("image/") ? 1 : 0);
        fileInfo.setSize(file.getSize());
        fileInfo.setCreateTime(LocalDateTime.now());
        return fileInfo;
    }

    /**
     * 文件的md5
     * @param inputStream inputStream
     * @return String
     */
    public static String fileMd5(InputStream inputStream) {
        try {
            return DigestUtils.md5Hex(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存文件到指定地址
     * @param file 文件
     * @param path 目的地址
     * @return String
     */
    public static boolean uploadFile(MultipartFile file, String path){
        try {
            File targetFile = new File(path);
            if (targetFile.exists()){
                throw new IllegalArgumentException("[" + path + "]路径已经存在");
            }
            if (!targetFile.getParentFile().exists()){
                targetFile.getParentFile().mkdirs();
            }

            file.transferTo(targetFile);

            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 删除文件
     * @param pathName 路径名
     * @return boolean
     */
    public static boolean deleteFile(String pathName){
        File file = new File(pathName);
        if (file.exists()){
            return file.delete();
        }
        return false;
    }

    /**
     * 检查path，如果没有以分隔符结尾，则增加分隔符
     * @param path 路径
     * @return String
     */
    private static String checkPath(String path){
        Objects.requireNonNull(path, "upload path cannot be empty");
        if (!path.endsWith(File.separator)){
            return path + File.separator;
        }
        return path;
    }

    /**
     * 获取文件扩展名
     * @param fileName 文件名
     * @return String
     */
    public static String getExtension(String fileName){
        Objects.requireNonNull(fileName, "filename cannot be empty");
        if (fileName.contains(".")){
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }
        return fileName;
    }

}